﻿using AbpDemo.Admins.Dto;
using AbpDemo.Utility;
using IdentityModel;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.ObjectMapping;

namespace AbpDemo.Admins
{
    [ApiExplorerSettings(GroupName = "v1")]
    [Authorize]    
    public class AdminService : ApplicationService, IAdminService
    {
        private readonly IRepository<Admin> repository;
        private readonly IConfiguration configuration;
        private readonly IAdminRepository adminRepository;
        private readonly IHttpContextAccessor httpContext;

        public AdminService(
            IRepository<Admin> repository,
            IConfiguration configuration,
            IAdminRepository adminRepository,
            IHttpContextAccessor httpContext
            )
        {
            this.repository = repository;
            this.configuration = configuration;
            this.adminRepository = adminRepository;
            this.httpContext = httpContext;
        }

        /// <summary>
        /// 创建用户
        /// </summary>
        /// <param name="registerDto"></param>
        /// <returns></returns>
        [HttpPost("/Admin/Create")]
        [AllowAnonymous]
        public async Task<RegisterResultDto> CreateAsync(RegisterDto registerDto)
        {
            try
            {
                var admin = await repository.FirstOrDefaultAsync(m=>m.UserName == registerDto.UserName);
                if(admin != null)
                {
                    return new RegisterResultDto { Code = RegisterState.UserNameExists, Message = RegisterState.UserNameExists.EnumToDescription() };
                }
                registerDto.Password = registerDto.Password.Md5();
                var entity = ObjectMapper.Map<RegisterDto, Admin>(registerDto);
                await repository.InsertAsync(entity);
                return new RegisterResultDto { Code = RegisterState.Success, Message = RegisterState.Success.EnumToDescription() };
            }
            catch (Exception e)
            {
                return new RegisterResultDto { Code = RegisterState.Failed, Message = e.Message };
            }
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="adminDto"></param>
        /// <returns></returns>
        [HttpPost("/Admin/Login")]
        [AllowAnonymous]
        public async Task<LoginResultDto> LoginAsync(LoginDto adminDto)
        {
            try
            {
                var admin = await repository.FirstOrDefaultAsync(m => m.UserName == adminDto.UserName);
                if (admin == null)
                {
                    return new LoginResultDto { Code = LoginState.NotFoundUserName, Message = LoginState.NotFoundUserName.EnumToDescription() };
                }
                else
                {
                    //如果达到解锁条件，则更新锁定状态
                    if (admin.IsLock && DateTime.Now.Subtract((DateTime)admin.LockTime).TotalSeconds > 30)
                    {
                        admin.IsLock = false;
                        admin.LockTime = null;
                        admin.ErrorLoginNum = 0;
                        await repository.UpdateAsync(admin);
                    }

                    //锁定时间小于30分钟并且在锁定状态
                    if (admin.IsLock && DateTime.Now.Subtract((DateTime)admin.LockTime).TotalSeconds < 30)
                    {
                        return new LoginResultDto { Code = LoginState.Locked, Message = LoginState.Locked.EnumToDescription() };
                    }
                    else
                    {
                        if (admin.Password != adminDto.Password.Md5())
                        {
                            admin.ErrorLoginNum += 1;

                            if (admin.ErrorLoginNum >= 5)
                            {
                                admin.IsLock = true;
                                admin.LockTime = DateTime.Now;

                                //锁定用户
                                await repository.UpdateAsync(admin);

                                

                                return new LoginResultDto { Code = LoginState.Locked, Message = LoginState.Locked.EnumToDescription() };
                            }

                            return new LoginResultDto { Code = LoginState.PasswordWrong, Message = LoginState.PasswordWrong.EnumToDescription() };
                        }
                        else
                        {
                            //更新末次登录IP和末次登录时间
                            admin.LastLoginIp = httpContext.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
                            admin.LastLoginTime = DateTime.Now;
                            admin.ErrorLoginNum = 0;
                            await repository.UpdateAsync(admin);

                            IList<Claim> claims = new List<Claim> {
                            new Claim(JwtClaimTypes.Id, admin.Id.ToString()),
                            new Claim(JwtClaimTypes.Name, admin.UserName)
                            };

                            //JWT密钥
                            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtConfig:Bearer:SecurityKey"]));

                            //算法
                            var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                            //过期时间
                            DateTime expires = DateTime.UtcNow.AddHours(10);

                            //Payload负载
                            var token = new JwtSecurityToken(
                                issuer: configuration["JwtConfig:Bearer:Issuer"],
                                audience: configuration["JwtConfig:Bearer:Audience"],
                                claims: claims,
                                notBefore: DateTime.UtcNow,
                                expires: expires,
                                signingCredentials: cred
                                );

                            var handler = new JwtSecurityTokenHandler();

                            //生成令牌
                            string jwt = handler.WriteToken(token);

                            return new LoginResultDto { Code = LoginState.Success, Token = jwt };
                        }
                    }
                }
            }
            catch (Exception e)
            {
                return new LoginResultDto { Code = LoginState.Failed, Message = e.Message };
            }            
        }

        [HttpGet("/Admin/Info")]
        [AllowAnonymous]
        public ResultDto<AdminInfo> Info(string Token)
        {
            return new ResultDto<AdminInfo>
            {
                Code = ResultState.Success,
                Data = new AdminInfo
                {
                    avatar = "/avatar",
                    introduction = "说明信息",
                    name = "admin",
                    roles = new string[]{ "admin" }
                }
            };
        }
    }
}
